﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Sublimation
{
    public class UpgradeTree : GameObject
    {
        private UpgradeNode upgradeRoot;
        public UpgradeNode UpgradeRoot
        {
            get 
            {
                UpgradeNode newNode = new UpgradeNode(worldProperties, upgradeRoot.Kind, upgradeRoot.Name, upgradeRoot.Description, upgradeRoot.Sprite, upgradeRoot.Position, upgradeRoot.ChildUpgrades);
                return newNode;  
            }
        }
        private UpgradeNode mainWeaponNode;
        public UpgradeNode MainWeaponNode
        {
            get
            {
                UpgradeNode newNode = new UpgradeNode(worldProperties, mainWeaponNode.Kind, mainWeaponNode.Name, mainWeaponNode.Description, upgradeRoot.Sprite, mainWeaponNode.Position, mainWeaponNode.ChildUpgrades);
                return mainWeaponNode;
            }
        }
        private UpgradeNode energyTransferNode;
        public UpgradeNode EnergyTransferNode
        {
            get
            {
                UpgradeNode newNode = new UpgradeNode(worldProperties, energyTransferNode.Kind, energyTransferNode.Name, energyTransferNode.Description, energyTransferNode.Sprite, upgradeRoot.Position, energyTransferNode.ChildUpgrades);
                return energyTransferNode;
            }
        }
        private Texture2D sniper1;
        private Texture2D flame_throw1;
        private Texture2D mine1;
        private Texture2D needle_gun;
        private Texture2D shield1;
        private Texture2D weapon1;
        private Texture2D weapon2;
        private Texture2D energy1;
        private Texture2D lightFence1;
        private Texture2D attract1;
        private Texture2D repulsor1;

        private UpgradeNode[,] visibleUpgrades;
        public UpgradeNode[,] VisibleUpgrades
        {
            set { visibleUpgrades = value; }
            get { return visibleUpgrades; }
        }

        private int selectedSlot;
        public int SelectedSlot
        {
            set { selectedSlot = value; }
            get { return selectedSlot; }
        }
        public UpgradeTree(WorldProperties worldProperties)
            :base(worldProperties)
        {
           // needle gun branch
           UpgradeNode sniperNode = new UpgradeNode(worldProperties, SlotKind.Sniper, "Sniper", "Sniper: unlimited range and high damage but slow", sniper1, Vector2.Zero, null);

           // flame thrower branch
           UpgradeNode flameThrowerNode = new UpgradeNode(worldProperties, SlotKind.Flame, "Frame Thrower", "Frame Thrower: fast and cover all it's angle but limited range", flame_throw1, Vector2.Zero, null);
           
            // mine layer branch
           UpgradeNode mineLayerNode = new UpgradeNode(worldProperties, SlotKind.Mine, "Mine Layer", "Mine Layer: create a mine field over time", mine1, Vector2.Zero, null);
           
           // needle guns branch
           List<UpgradeNode> needleChildren = new List<UpgradeNode>();
           needleChildren.Add(sniperNode);
           needleChildren.Add(flameThrowerNode);
           needleChildren.Add(mineLayerNode);
           UpgradeNode needleGunNode = new UpgradeNode(worldProperties, SlotKind.NeedleGun, "Needle Gun", "Needle Gun: very fast gun", needle_gun, Vector2.Zero, needleChildren);
           
           // shield branch
           UpgradeNode shieldNode = new UpgradeNode(worldProperties, SlotKind.Sheild, "Shield", "Shield: Improve the shield significantly", shield1, Vector2.Zero, null); 

           // weapon branch
           UpgradeNode weaponNode = new UpgradeNode(worldProperties, SlotKind.Weapon_up, "Weapon Upgrade", "Weapon Upgrade: improve rate range and damage of all the tower weapon", shield1, Vector2.Zero, null);

           // energy branch
           UpgradeNode energyNode = new UpgradeNode(worldProperties, SlotKind.Energy_up, "Energy", "Energy: increase energy production", energy1, Vector2.Zero, null);
           List<UpgradeNode> energyChildren = new List<UpgradeNode>();
           energyChildren.Add(energyNode);
           energyChildren.Add(shieldNode);
           energyChildren.Add(weaponNode);
           UpgradeNode generalUpNode = new UpgradeNode(worldProperties, SlotKind.General_up, "General Upgrade", "General Upgrade: Create a shield, improve energy production and all weapon are fast and more dangerous", shield1, Vector2.Zero, energyChildren);

            // lightning fence branch
           UpgradeNode lightFenceNode = new UpgradeNode(worldProperties, SlotKind.Lightning, "Lightning Fence", "Lightning Fence: build two on two towers and make a dealy lightning fence by directing them at each other", lightFence1, Vector2.Zero, null);
           
           // attractor branch
           List<UpgradeNode> attractChildren = new List<UpgradeNode>();
           attractChildren.Add(lightFenceNode);
           UpgradeNode attractorNode = new UpgradeNode(worldProperties, SlotKind.Attractor, "Attractor", "Attractor", attract1, Vector2.Zero, attractChildren);
           UpgradeNode attractorFreeNode = new UpgradeNode(worldProperties, SlotKind.AttractorFree, "Attractor", "Attractor: attract enemies to your tower", attract1, Vector2.Zero, attractChildren);
           

           // repulsor branch
           List<UpgradeNode> repulsorChildren = new List<UpgradeNode>(); 
           repulsorChildren.Add(lightFenceNode);
           repulsorChildren.Add(attractorFreeNode);
           UpgradeNode repulsorNode = new UpgradeNode(worldProperties, SlotKind.Repulsor, "Repulsor", "Repulsor: Repulse enemies away from  your tower", repulsor1, Vector2.Zero, repulsorChildren);
           UpgradeNode repulsorFreeNode = new UpgradeNode(worldProperties, SlotKind.RepulsorFree, "Repulsor", "Repulsor: go back to repulsor for free", repulsor1, Vector2.Zero, repulsorChildren);


           // you can also go back between attractor to repulsor free
           attractorNode.ChildUpgrades = new List<UpgradeNode>();
           attractorNode.ChildUpgrades.Add(repulsorFreeNode);

           // finally link them to root node
           List<UpgradeNode> rootChildren = new List<UpgradeNode>();
           rootChildren.Add(needleGunNode);
           rootChildren.Add(generalUpNode);
           rootChildren.Add(repulsorNode);
           upgradeRoot = new UpgradeNode(worldProperties, rootChildren);
           upgradeRoot.Name = "Root";
           upgradeRoot.Kind = SlotKind.Empty;

           //Main Weapon
           List<UpgradeNode> mainWeaponChildren = new List<UpgradeNode>();
           UpgradeNode mainWeapon2Node = new UpgradeNode(worldProperties, SlotKind.Base_weapon2, "Main weapon II", "Main weapon II: Improve the rate and damage of the main weapon", weapon2, Vector2.Zero, null);
           mainWeaponChildren.Add(mainWeapon2Node);
           mainWeaponNode = new UpgradeNode(worldProperties, SlotKind.Base_weapon, "Main weapon", "Main weapon", weapon1, Vector2.Zero, mainWeaponChildren);

           //Energy transfer
           List<UpgradeNode> energyTransferChildren = new List<UpgradeNode>();
           UpgradeNode energyTransfer2Node = new UpgradeNode(worldProperties, SlotKind.Energy_transmition2, "Energy transmission II", "Energy transmission II: improve speed of energy transmission", energy1, Vector2.Zero, null);
           energyTransferChildren.Add(energyTransfer2Node);
           energyTransferNode = new UpgradeNode(worldProperties, SlotKind.Energy_transmition, "Energy transmission", "Energy transmission", energy1, Vector2.Zero, energyTransferChildren);

           visibleUpgrades = new UpgradeNode[6, 3];

           //selectedSlot = - 1;
           Scale = 1.0f;
        }

        public List<UpgradeNode> GetRootUpgrades(UpgradeNode rootNode)
        {
            List<UpgradeNode> newList = new List<UpgradeNode>();

            List<UpgradeNode> tempList = rootNode.ChildUpgrades;
            // copy the list
            if (tempList != null)
            {
                foreach (UpgradeNode aNode in tempList)
                {
                    UpgradeNode newNode = new UpgradeNode(worldProperties, aNode.Kind, aNode.Name, aNode.Description, aNode.Sprite, aNode.Position, aNode.ChildUpgrades);
                    // make it visible
                    newNode.Scale = 1f;
                    newList.Add(newNode);
                }
            }

            return newList;
        }

        public List<UpgradeNode> GetAvailableUpgrades(UpgradeNode rootNode, String name)
        {
            List<UpgradeNode> newList = new List<UpgradeNode>();
            
            // find the upgrade
            UpgradeNode upgrade = FindUpgrade(rootNode, name);

            // get its children
            List<UpgradeNode> tempList = upgrade.ChildUpgrades;

            // copy the list
            if (tempList != null)
            {
                foreach (UpgradeNode aNode in tempList)
                {
                    UpgradeNode newNode = new UpgradeNode(worldProperties, aNode.Kind, aNode.Name, aNode.Description, aNode.Sprite, aNode.Position, aNode.ChildUpgrades);
                    // make it visible
                    newNode.Scale = 1f;
                    newList.Add(newNode);
                }
            }
            
            return (newList);
        }

        // Uses breadth first search to find the item
        public UpgradeNode FindUpgrade(UpgradeNode rootNode, String name)
        {
            Queue<UpgradeNode> searchQueue = new Queue<UpgradeNode>();
            searchQueue.Enqueue(rootNode);

            while (searchQueue.Count != 0)
            {
                UpgradeNode curNode = searchQueue.Dequeue();
                if (curNode.Name == name)
                {
                    return curNode;
                }
                else
                {
                    List<UpgradeNode> children = curNode.ChildUpgrades;
                    if (children != null)
                    {
                        foreach (UpgradeNode aNode in children)
                            searchQueue.Enqueue(aNode);
                    }
                }
            }
            return null;
        }

        public UpgradeNode FindUpgrade(UpgradeNode rootNode, SlotKind kind)
        {
            Queue<UpgradeNode> searchQueue = new Queue<UpgradeNode>();
            searchQueue.Enqueue(rootNode);

            while (searchQueue.Count != 0)
            {
                UpgradeNode curNode = searchQueue.Dequeue();
                if (curNode.Kind == kind)
                {
                    return curNode;
                }
                else
                {
                    List<UpgradeNode> children = curNode.ChildUpgrades;
                    if (children != null)
                    {
                        foreach (UpgradeNode aNode in children)
                            searchQueue.Enqueue(aNode);
                    }
                }
            }
            return null;
        }

        protected override void LoadContent()
        {
            base.LoadContent();
            needle_gun = Game.Content.Load<Texture2D>("Sprites/Upgrades/needle_gun");
            sniper1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/sniper1");
            flame_throw1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/flame_throw1");
            mine1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/mine1");
            energy1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/energy1");
            shield1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/shield1");
            weapon1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/weapon1");
            weapon2 = Game.Content.Load<Texture2D>("Sprites/Upgrades/weapon2");
            lightFence1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/lightFence1");
            repulsor1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/repulsor1");
            attract1 = Game.Content.Load<Texture2D>("Sprites/Upgrades/attract1");
        }
    }
}
